﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace Asset
{
    public class ResPool : Singleton<ResPool>
    {
        private Dictionary<string, IAsyncBundle> map = new Dictionary<string, IAsyncBundle>();
        private Dictionary<string, BasePool> prefabMap = new Dictionary<string, BasePool>();
        public List<IAsyncBundle> bundleWaitingLst = new List<IAsyncBundle>();
        public List<IAsyncBundle> bundleRuningLst = new List<IAsyncBundle>();

        public List<IAsyncAsset> assetWaitingLst = new List<IAsyncAsset>();
        public List<IAsyncAsset> assetRuningLst = new List<IAsyncAsset>();

        #region Asset 加载相关        
        public AsyncAsset<T> loadAssetAsync<T>(string resUrl, string resName) where T : UnityEngine.Object
        {
            IAsyncBundle asyncBundle;
            if (!map.TryGetValue(resUrl, out asyncBundle))
            {
#if DEVELOP
                asyncBundle = new EditorAsyncBundle(resUrl);
#else
                asyncBundle = new AsyncBundle(resUrl);
#endif
                addBundle(asyncBundle);
            }
            return asyncBundle.loadAssetAsync<T>(resName);
        }
        public T loadAsset<T>(string resUrl, string resName) where T : UnityEngine.Object
        {
            IAsyncBundle asyncBundle;
            if (!map.TryGetValue(resUrl, out asyncBundle))
            {
#if DEVELOP
                asyncBundle = new EditorBundle(resUrl);
#else
                asyncBundle = new Bundle(resUrl);
#endif
                addBundle(asyncBundle);
            }
            return asyncBundle.loadAsset<T>(resName);
        }

        public AsyncSceneBundle loadSceneBundle(string sceneName)
        {
            IAsyncBundle asyncBundle;
            string resUrl = PoolMgr.Instance.getAssetUrl(sceneName);
            if (!map.TryGetValue(resUrl, out asyncBundle))
            {
                asyncBundle = new AsyncSceneBundle(resUrl);
                addBundle(asyncBundle);
            }
            return asyncBundle as AsyncSceneBundle;
        }
        #endregion
        #region GameObject 加载相关
        public GameObject instantiateObj(string resUrl, string resName, Pool_Type poolType = Pool_Type.None)
        {
            BasePool pool;
            if (!prefabMap.TryGetValue(resUrl, out pool))
            {
                pool = new BasePool(resUrl, resName);
                prefabMap.Add(resUrl, pool);
            }
            return pool.getObj();
        }
        public void instantiateObjAsync(string resUrl, string resName, Action<GameObject> callBack, Pool_Type poolType = Pool_Type.None)
        {
            BasePool pool;
            if (!prefabMap.TryGetValue(resUrl, out pool))
            {
                pool = new BasePool(resUrl, resName);
                prefabMap.Add(resUrl, pool);
            }
            pool.getObjAsync(callBack);
        }
        public void preInsObjAsync(string resUrl, string resName, int count, Action callBack, Pool_Type poolType = Pool_Type.None)
        {
            BasePool pool;
            if (!prefabMap.TryGetValue(resUrl, out pool))
            {
                pool = new BasePool(resUrl, resName);
                prefabMap.Add(resUrl, pool);
            }
            pool.preLoad(count, callBack);
        }
        public void unloadObj(string resUrl, string resName, Action<GameObject> callBack)
        {
            BasePool pool;
            if (prefabMap.TryGetValue(resUrl, out pool))
            {
                pool.unload(callBack);
            }
        }
        public void recyleObj(GameObject obj)
        {
            PoolObj poolObj = obj.GetComponent<PoolObj>();
            if (poolObj != null)
            {
                BasePool pool;
                if (prefabMap.TryGetValue(poolObj.ResUrl, out pool))
                {
                    pool.recyleObj(obj);
                }
                else
                {
                    GameObject.Destroy(obj);
                }
            }
            else
            {
                GameObject.Destroy(obj);
            }
        }

        public Dictionary<string, BasePool>.Enumerator getPoolEator()
        {
            return prefabMap.GetEnumerator();
        }
        #endregion

        int preLoadNeedNum = 0;
        int preLoadNowNum = 0;
        Action<int> progressHandler;
        public IEnumerator loadSceneAsync(string sceneName, Action<int> progressHandler, List<PreLoadInfo> preLoad = null)
        {
            preLoadNeedNum = 0;
            preLoadNowNum = 0;
            this.progressHandler = progressHandler;

            int nowProgress = 0;
            AsyncOperation op = SceneManager.LoadSceneAsync(sceneName);
            while (!op.isDone)
            {
                nowProgress = (int)(op.progress * 90);
                progressHandler(nowProgress);
                yield return new WaitForEndOfFrame();
            }

            if (preLoad != null && preLoad.Count > 0)
            {
                preLoadNeedNum = preLoad.Count;
                for (int i = 0; i < preLoad.Count; i++)
                {
                    string resName = preLoad[i].resName;
                    int count = preLoad[i].count;
                    string url = PoolMgr.Instance.getAssetUrl(resName);
                    this.preInsObjAsync(url, resName, count, onPreLoadFinish);
                }
            }
            else
            {
                progressHandler(100);
            }
            yield break;
        }

        private void onPreLoadFinish()
        {
            preLoadNowNum++;
            int progress = 90 + (int)((preLoadNowNum / preLoadNeedNum) * 0.1f);
            if (this.preLoadNowNum >= this.preLoadNeedNum)
            {
                progress = 100;
            }
            this.progressHandler(progress);
        }

        public Dictionary<string, IAsyncBundle>.Enumerator getBundleEator()
        {
            return map.GetEnumerator();
        }

        public void unloadBunle(IAsyncBundle bundle)
        {
            if (this.map.ContainsKey(bundle.URL))
            {
                this.map.Remove(bundle.URL);
            }
            bundle.unload();
        }

        public void addBundle(IAsyncBundle bundle, bool firstPriorty = false)
        {
            if (!map.ContainsKey(bundle.URL))
                map.Add(bundle.URL, bundle);
            if (bundle.Status == AsyncStatus.Waiting)
            {
                if (firstPriorty)
                {
                    bundleWaitingLst.Insert(0, bundle);
                }
                else
                {
                    bundleWaitingLst.Add(bundle);
                }
            }
        }

        public IAsyncBundle getBundle(string resUrl)
        {
            IAsyncBundle option;
            if (map.TryGetValue(resUrl, out option))
            {
                return option;
            }
            return null;
        }

        public bool hasBundle(string resUrl)
        {
            return map.ContainsKey(resUrl);
        }

        //Asset 添加队列
        public void addWaitingAsset(IAsyncAsset asyncBundle)
        {
            if (asyncBundle.Status == AsyncStatus.Waiting)
            {
                assetWaitingLst.Add(asyncBundle);
            }
        }
    }

}
